﻿using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleSample.Tools.IO
{
    public static class DirectoryHelper
    {
        public static void CopyDirectory(string srcPath, string dstPath)
        {
            if (!Directory.Exists(srcPath))
            {
                return;
            }

            if (!Directory.Exists(dstPath))
            {
                Directory.CreateDirectory(dstPath);
            }

            if (!Directory.Exists(dstPath))
            {
                return;
            }

            srcPath = srcPath.Replace('\\', '/');
            srcPath = srcPath.TrimEnd('/');
            srcPath += '/';

            dstPath = dstPath.Replace('\\', '/');
            dstPath = dstPath.TrimEnd('/');
            dstPath += '/';

            //获取原文件夹下所有的文件
            var files = Directory.GetFileSystemEntries(srcPath);
            foreach (var file in files)
            {
                var relative = file.Substring(srcPath.Length);

                //如果是文件夹，递归拷贝文件夹
                if (Directory.Exists(file))
                {
                    CopyDirectory(file, dstPath + relative);
                    continue;
                }

                var dstFileName = Path.Combine(dstPath, relative);
                if (File.Exists(dstFileName))
                {
                    File.Delete(dstFileName);
                }

                var fileInfo = new FileInfo(file);
                fileInfo.CopyTo(dstFileName, true);
            }
        }

        public static void MoveDirectory(string srcPath, string dstPath)
        {
            if (!Directory.Exists(srcPath))
            {
                return;
            }

            if (!Directory.Exists(dstPath))
            {
                Directory.CreateDirectory(dstPath);
            }

            if (!Directory.Exists(dstPath))
            {
                return;
            }

            srcPath = srcPath.Replace('\\', '/');
            srcPath = srcPath.TrimEnd('/');
            srcPath += '/';

            dstPath = dstPath.Replace('\\', '/');
            dstPath = dstPath.TrimEnd('/');
            dstPath += '/';

            //获取原文件夹下所有的文件
            var files = Directory.GetFileSystemEntries(srcPath);
            foreach (var file in files)
            {
                var relative = file.Substring(srcPath.Length);

                //如果是文件夹，递归拷贝文件夹
                if (Directory.Exists(file))
                {
                    MoveDirectory(file, dstPath + relative);
                    continue;
                }

                var dstFileName = Path.Combine(dstPath, relative);
                File.Move(file, dstFileName);
            }

            ClearDirectory(srcPath);
        }

        public static bool ClearDirectory(string path, bool throwException = true)
        {
            if (!Directory.Exists(path))
            {
                return false;
            }

            path = path.Replace('\\', '/');
            path = path.TrimEnd('/');
            path += '/';

            var ret = true;

            //获取原文件夹下所有的文件
            var files = Directory.GetFileSystemEntries(path);
            foreach (var file in files)
            {
                //如果是文件夹，递归删除文件夹
                if (Directory.Exists(file))
                {
                    if (!DeleteDirectory(file))
                    {
                        ret = false;
                        break;
                    }
                }
                else
                {
                    InvokeAction(() => { File.Delete(file); }, throwException);
                }
            }

            return ret;
        }

        public static bool DeleteDirectory(string path, bool throwException = true)
        {
            if (!Directory.Exists(path))
            {
                return false;
            }

            path = path.Replace('\\', '/');
            path = path.TrimEnd('/');
            path += '/';

            var ret = true;

            //获取原文件夹下所有的文件
            var files = Directory.GetFileSystemEntries(path);
            foreach (var file in files)
            {
                //如果是文件夹，递归删除文件夹
                if (Directory.Exists(file))
                {
                    if (!DeleteDirectory(file))
                    {
                        ret = false;
                        break;
                    }
                }
                else
                {
                    InvokeAction(() => { File.Delete(file); }, throwException);
                }
            }

            InvokeAction(() => { Directory.Delete(path); }, throwException);
            return ret;
        }

        private static void InvokeAction(Action action, bool throwException = true)
        {
            try
            {
                action?.Invoke();
            }
            catch (Exception e)
            {
                if (throwException)
                {
                    throw new Exception(e.Message);
                }
            }
        }

        /// <summary>
        /// 获取文件夹中所有文件(夹)路径集合
        /// </summary>
        /// <param name="directory">目标文件夹路径</param>
        /// <param name="containsDirectory">是否包含文件夹路径</param>
        /// <returns>所有文件(夹)路径集合</returns>
        public static List<string> GetFileList(string directory, bool containsDirectory = true)
        {
            var currentList = new List<string>();
            if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory))
            {
                return currentList;
            }

            try
            {
                //遍历文件
                var files = Directory.GetFiles(directory);
                currentList.AddRange(files);

                //递归遍历子文件夹
                var subDirectories = Directory.GetDirectories(directory);
                foreach (var subDirectory in subDirectories)
                {
                    if (containsDirectory)
                    {
                        currentList.Add(subDirectory);
                    }

                    var subList = GetFileList(subDirectory, containsDirectory);
                    currentList.AddRange(subList);
                }
            }
            catch
            {
                currentList.Clear();
            }

            return currentList;
        }

        /// <summary>
        /// 获取文件夹中所有文件的大小
        /// </summary>
        /// <param name="directory">目标文件夹路径</param>
        /// <returns>文件夹中所有文件的大小</returns>
        public static long GetDirectorySize(string directory)
        {
            if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory))
            {
                return 0;
            }

            var totalFileSize = 0L;

            try
            {
                //递归遍历子文件夹
                var subDirectories = Directory.GetDirectories(directory);
                foreach (var subDirectory in subDirectories)
                {
                    totalFileSize += GetDirectorySize(subDirectory);
                }

                //遍历文件
                var files = Directory.GetFiles(directory);
                foreach (var file in files)
                {
                    totalFileSize += new FileInfo(file).Length;
                }
            }
            catch
            {
                totalFileSize = 0;
            }

            return totalFileSize;
        }
    }
}
